package com.innovation.action;


import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;

import java.security.NoSuchAlgorithmException;
import java.util.Map;

import org.apache.log4j.Logger;

import com.innovation.cache.PlayerCache;
import com.innovation.core.RequestSession;
import com.innovation.data.model.Player;
import com.innovation.exception.PatException;
import com.innovation.message.ClientActionProto.ClientAction;
import com.innovation.message.DataMsgProto.DataMsg;
import com.innovation.message.ErrorCodeProto.ErrorCode;
import com.innovation.message.ErrorMsgProto.ErrorMsg;
import com.innovation.message.PBMessageProto.PBMessage;
import com.innovation.service.PlayerService;
import com.innovation.util.MD5;
import com.innovation.util.MessageUtil;
import com.innovation.util.TimeUtil;

public abstract class BaseAction implements Action {

	private static final Logger logFlow = Logger.getLogger("FLOW");
	private static final Logger logger = Logger.getLogger(BaseAction.class);
	
	@Override
	public void run(RequestSession reqSession) throws Exception {
		//登录操作需要额外处理
		if(reqSession.getActionCode() == ClientAction.ACTION_LOGIN_VALUE){
			done(reqSession);
			send2Client(reqSession);
		}else{
			//初始化操作
			doInit(reqSession);
			Player player = reqSession.getPlayer();
			synchronized (player) {
				//所有提供的命令的都会调用
				access(reqSession);
				done(reqSession);
				//发送数据给客户端
				send2Client(reqSession);
			}
		}
	}

	/**
	 * 玩家访问(所有请求都会调用)
	 * @param reqSession
	 */
	protected void access(RequestSession reqSession) {
		Player player = reqSession.getPlayer();
		player.setAccessTime(TimeUtil.now());
		if (player.getChannel() != null && player.getChannel() != reqSession.getChannel()) {
			PlayerService.notifyLogout(player, ErrorCode.ERR_OTHER_LOGIN_VALUE);
			logger.info("close connection:playerId="+player.getId()+" openId="+player.getOpenId());
		}
		player.setChannel(reqSession.getChannel());
//		
//		//恢复战斗点
//		PlayerService.resumeBattlePoint(player);
//		
//		//每日重置数据
//		PlayerService.resetPlayerDailyData(player);
	}

	/**
	 * 初始化操作
	 * @param reqSession
	 * @throws PatException
	 * @throws NoSuchAlgorithmException 
	 * @throws Exception 
	 */
	protected void doInit(RequestSession reqSession) throws Exception{
		int playerId = reqSession.getPlayerId();
		if (playerId <= 0) {
			throw new PatException("player id is error");
		}
		
//		//非法请求
//		if(!verifySession(reqSession)){
//			throw new PpseaException("illegal request");
//		}
		
		Player player = PlayerCache.INSTANCE.getOnlinePlayer(playerId);
		Player newPlayer = player;
		if (newPlayer == null) {
//			newPlayer = PlayerService.loadPlayerById(playerId);
		}

		if (newPlayer == null) {
			throw new PatException("player not exists. playerId=" + playerId);
		}
		
		if(player == null){
			logger.warn("player not found on cache: playerId="+playerId);
//			player = PlayerService.login(playerId);
		}
		
		reqSession.setPlayer(player);
		
		
		//设置日志信息
		initLogData(reqSession);
	}
	
	/**
	 * 返回数据给客户端
	 * @param reqSession
	 */
	protected void send2Client(RequestSession reqSession){
		try{
			Channel channel = reqSession.getChannel();
			PBMessage.Builder body = reqSession.getResponse();
			
			//检查推送的数据是否为空
			Player player = reqSession.getPlayer();
			if(player != null){
				synchronized (player.getDataMsg()) {
					DataMsg.Builder dataMsg = player.getDataMsg();
					dataMsg.setNow(TimeUtil.now());
					DataMsg msg = dataMsg.build();
					if(msg.getSerializedSize() > 0){
						body.setDataMsg(msg);
						player.getDataMsg().clear();
					}
				}
			}
			PBMessage response = body.build();
			ByteBuf buf = Unpooled.buffer(response.getSerializedSize());
			buf.writeBytes(response.toByteArray());
			channel.writeAndFlush(new BinaryWebSocketFrame(buf));
			//解锁玩家操作
			if(reqSession.getPlayerId() > 0){
				PlayerCache.INSTANCE.unLock(reqSession.getPlayerId());
			}
		} finally{
			//记录流水日志
			logFlow(reqSession);
		}
	}
	
	/**
	 * 发送错误信息
	 * @param reqSession
	 * @param errMsg
	 */
	protected void sendErrorMsg(RequestSession reqSession, int errorCode, Object... args){
		ErrorMsg errMsg = MessageUtil.buildErrorMsg(errorCode, args);
		sendErrorMsg(reqSession, errMsg);
	}
	
	/**
	 * 发送错误信息给客户端
	 * @param reqSession
	 * @param errMsg
	 */
	protected void sendErrorMsg(RequestSession reqSession, ErrorMsg errMsg){
		PBMessage.Builder response = reqSession.getResponse();
		response.setErrorCode(errMsg.getCode());
		response.setData(errMsg.toByteString());
		reqSession.setResult("fail");
	}
	
	/**
	 * 初始化日志
	 * @param reqSession
	 */
	protected void initLogData(RequestSession reqSession) {
		Map<Integer, Long> logData = reqSession.getLogData();
		Player player = reqSession.getPlayer();
		logData.put(FLOW_GOLD, (long)player.getGold());
		logData.put(FLOW_MONEY, (long)player.getMoney());
//		logData.put(FLOW_SOUL, (long)player.getSoul());
	}
	/**
	 * 记录流水日志
	 * @param reqSession
	 */
	protected void logFlow(RequestSession reqSession){
		Map<Integer, Long> logData = reqSession.getLogData();
		if(logData != null && logData.size() > 0){
			StringBuilder logContent = new StringBuilder();
			Player player = reqSession.getPlayer();
			logContent.append(player.getId()).append("|");//玩家id
			logContent.append(player.getOpenId()).append("|");//玩家平台id
			logContent.append(reqSession.getActionCode()).append("|");//玩家操作码
			logContent.append(System.currentTimeMillis() - reqSession.getRecvTime()).append("|");//命令执行时间
			logContent.append(reqSession.getResult()).append("|");
			logContent.append(player.getGold()-logData.get(FLOW_GOLD)).append("|");//人民币变化
			logContent.append(player.getMoney() - logData.get(FLOW_MONEY));//游戏币变化
//			logContent.append(player.getSoul() - logData.get(FLOW_SOUL));//魂力变化
			logFlow.debug(logContent.toString());
		}
	}
	/**
	 * 子类实现(每个操作的具体逻辑)
	 * @param reqSession
	 */
	protected abstract void done(RequestSession reqSession) throws Exception;
	
	/**
	 * 校验请求的合法性(合法则返回true)
	 * @param reqSession
	 * @return
	 * @throws Exception 
	 */
	protected boolean verifySession(RequestSession reqSession) throws Exception {
		PBMessage.Builder tempMsg = PBMessage.newBuilder(reqSession.getRequest());
		String sessionKey = tempMsg.getSessionKey();
		tempMsg.clearSessionKey();
		byte[] data = tempMsg.build().toByteArray();
		
		String key = MD5.encode(data);
		System.out.println(sessionKey+"-----"+key);
		
		return sessionKey.equals(key);
	}
}
